package com.koron.gateway.filter;

import com.koron.gateway.ticket.utils.IpUtils;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * @ClassName HttpRequestFilter
 * @description 请求GET, POST 参数可以做记录日志
 * @Author zhouj
 * @Date 2021/5/13 15:22
 */
// @Component
@Slf4j
@AllArgsConstructor
public class HttpRequestFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String method = request.getMethodValue();

        RequestPath path = request.getPath();
        String ipAddress = IpUtils.getIpAddress(request);
        //request为请求的request
        String device = getDevice(request.getHeaders().getFirst("User-Agent"));
        log.info("设备信息:{}", device);

        if ("POST".equals(method)) {
            //boby为空
            final Mono<Void> post_body = DataBufferUtils.join(exchange.getRequest().getBody()
                    .defaultIfEmpty(new DefaultDataBufferFactory().allocateBuffer()))
                    .flatMap(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        String bodyString = new String(bytes, StandardCharsets.UTF_8);
                        String value = request.getHeaders().getFirst("Content-Type");
                        //付工报表来的 特殊处理一下
                        if ("content=text/html;charset=ANSI".equals(value)) {
                            value = MediaType.TEXT_HTML_VALUE;
                        }
                        MediaType contentType = StringUtils.hasLength(value) ? MediaType.parseMediaType(value) : null;

                        if (shouldRecordBody(contentType)) {
                            //非文件类打印出来
                            MultiValueMap<String, String> queryParams = request.getQueryParams();
                            log.info("客户端请求ip:{},请求路径:{},请求方式:{},请求params参数:{},请求boby参数:{}", ipAddress, path, method, queryParams.toString(), bodyString);
                        }
                        //可以记录到日志记录表
                        exchange.getAttributes().put("POST_BODY", bodyString);
                        DataBufferUtils.release(dataBuffer);
                        Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                            return Mono.just(buffer);
                        });

                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest)
                                .build());
                    });
            return post_body;
        } else if ("GET".equals(method)) {
            MultiValueMap<String, String> queryParams = request.getQueryParams();
            log.info("客户端请求ip:{},请求路径:{},请求方式:{},请求参数:{}", ipAddress, path, method, queryParams.toString());
            //可以记录到日志记录表
        }
        return chain.filter(exchange);
    }

    /**
     * 解析 用户代理(User-Agent)
     *
     * @param userAgent 用户代理User-Agent ,UA
     * @return "设备类型:%s,操作系统:%s,浏览器:%s,浏览器版本:%s,浏览器引擎:%s,用户代理(User-Agent):[%s]"
     * @author GongLiHai
     * @date 2020/8/25 11:12
     */
    private String getDevice(String userAgent) {
        //解析agent字符串
        UserAgent ua = UserAgent.parseUserAgentString(userAgent);
        //获取浏览器对象
        Browser browser = ua.getBrowser();
        //获取操作系统对象
        OperatingSystem os = ua.getOperatingSystem();
        return String.format("设备类型:%s,操作系统:%s,浏览器:%s,浏览器版本:%s,浏览器引擎:%s,用户代理(User-Agent):[%s]",
                os.getDeviceType(),
                os.getName(),
                browser.getName(),
                browser.getVersion(userAgent),
                browser.getRenderingEngine(),
                userAgent
        );
    }

    @Override
    public int getOrder() {
        return -1000000;
    }

    private boolean shouldRecordBody(MediaType contentType) {
        if (contentType == null) {
            return true;
        }
        String type = contentType.getType();
        String subType = contentType.getSubtype();

        if ("application".equals(type)) {
            return "json".equals(subType) || "x-www-form-urlencoded".equals(subType) || "xml".equals(subType) || "atom+xml".equals(subType) || "rss+xml".equals(subType);
        } else if ("text".equals(type)) {
            return true;
        }

        //暂时不记录form
        return false;
    }

}
